Ext.apply(Ext.DomHelper, function()
{
	var pub, afterbegin = 'afterbegin', afterend = 'afterend', beforebegin = 'beforebegin', beforeend = 'beforeend', confRe = /tag|children|cn|html$/i;

	/**
	 * el就是将要操作的元素 o 生成DOM的对象 returnElement 返回的元素 pos是位置(afterbegin,afterend,beforebegin,beforeend) sibling是邻居 append是否是追加
	 */
	function doInsert( el, o, returnElement, pos, sibling, append )
	{
		el = Ext.getDom(el);
		var newNode;

		if( pub.useDom )// 如果强制用DOM的话
		{
			newNode = createDom(o, null);
			if( append ) // 只有append，是true
			{
				el.appendChild(newNode);
			}
			else
			{
				// 从这里可以看出，如果要在元素之前或之后插入，得导航到父节点，使用insertBefore函数
				(sibling == 'firstChild' ? el : el.parentNode).insertBefore(newNode, el[sibling] || el);
			}
		}
		else
		{
			newNode = Ext.DomHelper.insertHtml(pos, el, Ext.DomHelper.createHtml(o));
		}
		return returnElement ? Ext.get(newNode, true) : newNode;
	}

	// build as dom
	/** @ignore */
	function createDom( o, parentNode )
	{
		var el, doc = document, useSet, attr, val, cn;

		if( Ext.isArray(o) ) // 创建一组兄弟节点
		{ // Allow Arrays of siblings to be inserted
			el = doc.createDocumentFragment(); // in one shot using a DocumentFragment
			for( var i = 0, l = o.length; i < l; i++ )
			{
				createDom(o[i], el);
			}
		}
		else if( typeof o == 'string' ) // 如果是个字符串，表明是个文本节点
		{ // Allow a string as a child spec.
			el = doc.createTextNode(o);
		}
		else
		{
			el = doc.createElement(o.tag || 'div');
			useSet = !!el.setAttribute; // IE中一些元素木有setAttribute方法
			for( var attr in o )
			{
				if( !confRe.test(attr) )
				{
					val = o[attr];
					if( attr == 'cls' ) // 如果是cls，那么就直接className=====
					{
						el.className = val;
					}
					else
					{
						// 设置属性
						if( useSet )
						{
							el.setAttribute(attr, val);
						}
						else
						{
							el[attr] = val;
						}
					}
				}
			}
			Ext.DomHelper.applyStyles(el, o.style);

			if( (cn = o.children || o.cn) ) // 如果有children属性，那么递归之（原来cn，就是children）
			{
				createDom(cn, el);
			}
			else if( o.html ) // 如果有htm属性，直接innerHTML
			{
				el.innerHTML = o.html;
			}
		}

		// 如果有parentNode，直接把el加进去
		if( parentNode )
		{
			parentNode.appendChild(el);
		}
		return el;
	}

	pub =
	{
		/**
		 * Creates a new Ext.Template from the DOM object spec.
		 * 
		 * @param {Object} o The DOM object spec (and children)
		 * @return {Ext.Template} The new template
		 */
		createTemplate: function( o )
		{
			var html = Ext.DomHelper.createHtml(o);
			return new Ext.Template(html);
		},

		// 若是true，则强制试用DOM的方式创建元素，否则用documentFragment
		useDom: false,

		// 在指定元素之前插入新元素，新元素可以通过配置对象生成
		insertBefore: function( el, o, returnElement )
		{
			return doInsert(el, o, returnElement, beforebegin);
		},

		// 在指定元素之后插入新元素，新元素可以通过配置对象生成
		insertAfter: function( el, o, returnElement )
		{
			return doInsert(el, o, returnElement, afterend, 'nextSibling');
		},

		// 在指定元素的内部首位置插入新元素，新元素可以通过配置对象生成
		insertFirst: function( el, o, returnElement )
		{
			return doInsert(el, o, returnElement, afterbegin, 'firstChild');
		},

		// 在指定元素的内部末尾插入新元素，新元素可以通过配置对象生成
		// 直接就是原生DOM的appendChild的功能吧
		// 最后一个标志位就是(是否是append)
		append: function( el, o, returnElement )
		{
			return doInsert(el, o, returnElement, beforeend, '', true);
		},

		createDom: createDom
	};
	return pub;
}());
